/**********************************************************************
 * SPRITE 2D class
 * by Marc-Henri Vuillaume
 **********************************************************************
 * * * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 **********************************************************************/

package mhv.fr.sprite;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;

/** The Sprite2D class define an abstract basic entity for graphic game elements.
 * @version Version 1.0
 * @author Marc-Henri Vuillaume
 */
public abstract class Sprite2D {

    GameEntity gameEntity;
    
    /** The drawing surface */
    private Graphics2D g2d;
    
    /** The transformation class */
    private AffineTransform identity;
    
    /** The sprite face angle */
    private double faceRotation;
    
    private boolean collided;

    public boolean isCollided() {
        return collided;
    }

    public void setCollided(boolean collided) {
        this.collided = collided;
    }

    public GameEntity getGameEntity() {
        return gameEntity;
    }

    public void setGameEntity(GameEntity gameEntity) {
        this.gameEntity = gameEntity;
    }

    /**
     * Getter method
     * @return boolean
     */
    public boolean isAlive() {
        return gameEntity.isAlive();
    }

    /**
     * Setter method
     * @param alive boolean
     */
    public void setAlive(boolean alive) {
        gameEntity.setAlive(alive);
    }

    /**
     * Getter method
     * @return double
     */
    public double getX() {
        return gameEntity.getX();
    }

    /**
     * Setter method
     * @param x double
     */
    public void setX(double x) {
        gameEntity.setX(x);
    }

    /**
     * Increase X coordinate
     * @param x double
     */
    public void incX(double x) {
        gameEntity.incX(x);
    }

    /**
     * Getter method
     * @return y double
     */
    public double getY() {
        return gameEntity.getY();
    }

    /**
     * Setter method
     * @param y boolean
     */
    public void setY(double y) {
        gameEntity.setY(y);
    }

    /**
     * Increase Y coordinate
     * @param y double
     */
    public void incY(double y) {
        gameEntity.incY(y);
    }

    /**
     * Getter method
     * @return double
     */
    public double getNextX() {
        return gameEntity.getNextX();
    }

    /**
     * Setter method
     * @param x double
     */
    public void setNextX(double x) {
        gameEntity.setNextX(x);
    }

    /**
     * Getter method
     * @return double
     */
    public double getNextY() {
        return gameEntity.getNextY();
    }

    /**
     * Setter method
     * @param x double
     */
    public void setNextY(double y) {
        gameEntity.setNextY(y);
    }

    /**
     * Getter method
     * @return int
     */
    public int getStatus() {
        return gameEntity.getStatus();
    }

    /**
     * Setter method
     * @param status int
     */
    public void setStatus(int status) {
        gameEntity.setStatus(status);
    }

    /**
     * Getter method
     * @return entity type
     */
    public int getType() {
        return gameEntity.getType();
    }

    /**
     * Setter method
     * @param type
     */
    public void setType(int type) {
        gameEntity.setType(type);
    }



    /**
     * Getter method
     * @return double
     */
    public double getRotation() {
        return gameEntity.getVelRotation();
    }

    /**
     * Setter method
     * @param rotation double
     */
    public void setRotation(double rotation) {
        gameEntity.setRotation(rotation);
    }

    /**
     * Getter method
     * @return double
     */
    public double getVelX() {
        return gameEntity.getVelX();
    }

    /**
     * Setter method
     * @param velX double
     */
    public void setVelX(double velX) {
        gameEntity.setVelX(velX);
    }

    /**
     * Getter method
     * @return double
     */
    public double getVelY() {
        return gameEntity.getVelY();
    }

    /**
     * Setter method
     * @param velY double
     */
    public void setVelY(double velY) {
        gameEntity.setVelY(velY);
    }

    /**
     * Increase X velocity
     * @param x double
     */
    public void incVelX(double x) {
        gameEntity.incVelX(x);
    }

    /**
     * Increase Y velocity
     * @param y double
     */
    public void incVelY(double y) {
        gameEntity.incVelY(y);
    }

    /**
     * Increase rotation
     * @param rotation double
     */
    public void incRotation(double rotation) {
        gameEntity.incRotation(rotation);
    }

    /**
     * Getter method
     * @return double
     */
    public double getVelRotation() {
        return gameEntity.getVelRotation();
    }

    /**
     * Setter method
     * @param velRotation double
     */
    public void setVelRotation(double velRotation) {
        gameEntity.setVelRotation(velRotation);
    }

    /**
     * Increase rotation velocity
     * @param velRotation double
     */
    public void incVelRotation(double velRotation) {
        gameEntity.incVelRotation(velRotation);
    }

    /**
     * Update the rotation by adding velocity
     */
    public void updateRotation() {
        gameEntity.updateRotation();
    }

    /**
     * Update the coordinate by adding velocity
     */
    public void updateMove() {
        gameEntity.updateMove();
    }

    /**
     * Getter method
     * @return double
     */
    public double getFaceRotation() {
        return faceRotation;
    }
    
    /**
     * Setter method 
     * @param faceRotation double
     */
    public void setFaceRotation(double faceRotation) {
        this.faceRotation = faceRotation;
    }
    
    /**
     * Increase face angle 
     * @param r double
     */
    public void incFaceRotation(double r) {
        this.faceRotation += r;
        faceRotation = faceRotation % 360;
    }

    /**
     * Get the bouning box of this Sprite2D
     * @return Rectangle
     */
    public abstract  Rectangle getBounds() ;

    /**
     * Getter method
     * @return Graphics2D
     */
    public Graphics2D getGraphics() {
        return g2d;
    }

    /**
     * Setter method 
     * @param g2d Graphics2D
     */
    public void setGraphics(Graphics2D g2d) {
        this.g2d = g2d;
    }
    
    /**
     * Apply transformation (translate, rotation) to this Sprite2D.
     */
    public void transform() {
        identity.setToIdentity();
        g2d.setTransform(identity);
        g2d.translate(getX(), getY());
        g2d.rotate(Math.toRadians(faceRotation));
    }

    /**
     * draw this Sprite2D into the drawing graphics surface.
     */
    public abstract void draw();
    
    /**
     * Check if this Spriped2D collided with an other sprite.
     * @param s Sprite2D
     * @return boolean
     */
    public boolean checkcollision(Sprite2D s) {
        return getBounds().intersects(s.getBounds());
    }
    
    /**
     * Check if this Spriped2D collided with a rectangle.
     * @param r Rectangle
     * @return boolean
     */
    public boolean checkcollision(Rectangle r) {
        return getBounds().intersects(r);
    }
    
    /**
     * Check if this Spriped2D collided with a point.
     * @param x double : the X point coordinate
     * @param y double : the Y point coordinate
     * @return boolean
     */
    public boolean checkcollision(double x, double y) {
        return getBounds().contains(x, y);
    }
    
    /**
     * Draw the bounding rectangle of this Sprite2D into the drawing surface.
     * @param c Color : the color of rectangle to draw
     */
    public void drawBounds(Color c) {
        identity.setToIdentity();
        g2d.setTransform(identity);
        g2d.setColor(c);
        g2d.drawRect(getBounds().x, getBounds().y, getBounds().width, getBounds().height);
    }
    
    /**
     * Construct and initialise the Sprite2D object.
     * @param g2d Graphics2D : the drawing surface
     */
    Sprite2D(Graphics2D g2d) {
        setGraphics(g2d);
        gameEntity = new GameEntity();
        faceRotation = 0;
        collided = false;
        identity = new AffineTransform();
    }
    


}
